package com.atguigu.security.filter;

import com.alibaba.fastjson.JSON;
import com.atguigu.common.jwt.JwtHelper;
import com.atguigu.common.result.ResponseUtil;
import com.atguigu.common.result.Result;
import com.atguigu.common.result.ResultCodeEnum;
import com.atguigu.model.system.SysUser;
import com.atguigu.security.custom.CustomUser;
import com.atguigu.vo.system.LoginVo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;

/**
 * ClassName: TokenLoginFilter
 * Package: com.atguigu.security.filter
 *
 * @Author: lmf
 * @Create: 2024/1/21 12:43
 * @Version: 1.0
 * Description:
 * UsernamePasswordAuthenticationFilter :  security
 */
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
    private RedisTemplate redisTemplate;
    /**
     * Constructor  构造器
     * @param authenticationManager authenticationManager
     */
    public TokenLoginFilter(AuthenticationManager authenticationManager,RedisTemplate redisTemplate) {
        this.setAuthenticationManager(authenticationManager)  ;
        this.setPostOnly(false);
        //指定登录接口及提交方式，可以指定任意路径
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/login/login", "POST"));
        this.redisTemplate = redisTemplate;
    }

    /**
     * 获取输入的用户名和密码，调用方法认证
     */
    public Authentication attemptAuthentication(
            HttpServletRequest request,
            HttpServletResponse response
    )
            throws AuthenticationException
    {
        try {
            // 获取用户信息
            final LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);
            //封装对象
            final UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
            // 调用方法进行认证
            return this.getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 认证成功的回调
     */
    public void successfulAuthentication(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain chain,
            Authentication authResult
    )   throws IOException,SecurityException{
        // 获取用户信息
        final CustomUser customUser = (CustomUser) authResult.getPrincipal();
        final SysUser sysUser = customUser.getSysUser();
        // 生成token
        final String token = JwtHelper.createToken(sysUser.getId(), sysUser.getUsername());
        // 获取氮气用户权限数据放到redis中
        redisTemplate.opsForValue().set(sysUser.getUsername(), JSON.toJSONString(customUser.getAuthorities()));
        // 返回token
        final HashMap<String, Object> data = new HashMap<>();
        data.put("token", token);
        ResponseUtil.out(response, Result.ok(data));
    }

    /**
     * 认证失败的回调
     */
    public void unsuccessfulAuthentication(
            HttpServletRequest request,
            HttpServletResponse response,
            AuthenticationException failed
    ) throws IOException,SecurityException{
        ResponseUtil.out(response, Result.build(null, ResultCodeEnum.LOGIN_ERROR));
    }
}
